package cn.mw.cmdb.processor;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.enums.ViewTypeEnum;
import cn.mw.cmdb.param.FunctionModuleEnum;
import cn.mw.cmdb.param.InstanceSearchParam;
import cn.mw.cmdb.param.ModelSearchParam;
import cn.mw.cmdb.param.TableSearchParam;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.CustomModelServiceImpl;
import cn.mw.cmdb.service.impl.InstanceServiceImpl;
import cn.mw.cmdb.service.impl.ModelPropertyServiceImpl;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.viewProcessor.RelateDataViewProcessor;
import cn.mw.cmdb.viewProcessor.ViewProcessorManage;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.microMonitorCommon.entity.cmdb.RelatedDataType;
import cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.util.CMDBTool.CMDBDefaultIdKey;
import static cn.mw.cmdb.util.CMDBTool.CMDBDefaultIdName;
import static cn.mw.microMonitorCommon.entity.cmdb.TableHeaderItem.flexNum;

@Slf4j
public class TableProcessorFinanceInstance implements TableDataProccessor {
    public static final String SEQ = "seq";

    private static final String SEQName = "序号";

    private CmdbServiceManage cmdbServiceManage;

    private TableSearchParam tableDataParam;

    private InstanceSearchParam instanceSearchParam;

    private List<String> tableHeaderSort;

    public TableProcessorFinanceInstance(CmdbServiceManage cmdbServiceManage, TableSearchParam tableDataParam,
                                         InstanceSearchParam instanceSearchParam, List<String> tableHeaderSort) {
        this.cmdbServiceManage = cmdbServiceManage;
        this.tableDataParam = tableDataParam;
        this.instanceSearchParam = instanceSearchParam;
        this.tableHeaderSort = tableHeaderSort;
    }

    @Override
    public List genData(TableDataProcessorContext context) throws Exception {
        long time1 = System.currentTimeMillis();
        InstanceServiceImpl instanceService = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        List<InstanceInfoExtend> instanceInfos = new ArrayList<>();
        //忽略null值注入
        BeanUtil.copyProperties(tableDataParam, instanceSearchParam, CopyOptions.create().setIgnoreNullValue(true));

        // 先查询分组下所有金融元父模型
        CustomModelServiceImpl customModelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        // 查询所有金融元父模型的普通模型
        ModelSearchParam parentModelSearchParam = new ModelSearchParam();
        parentModelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule), new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
        List<ModelInfo> financeParentModelInfos = customModelService.getAllModelByParentGroup(parentModelSearchParam);
        Map<String, ModelInfo> financeModelId2InfoMap = financeParentModelInfos.stream().collect(Collectors.toMap(ModelInfo::getId, item -> item, (o1, o2) -> o2));
        if (tableDataParam.getId().contains("_")) {
            // 列表接口通过分组id+金融元父模型id查询 金融元tableid为分组id+模型id
            instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getGroupId)
                    , new SubCondition(CriteriaOpsType.is.name(), tableDataParam.getId().split("_")[0]));
            instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getFinanceParentId)
                    , new SubCondition(CriteriaOpsType.is.name(), tableDataParam.getId().split("_")[1]));
        } else {
            // lookInstance接口通过模型id及金融元父模型id查询实例
            instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getModelId),
                    new SubCondition(CriteriaOpsType.is.name(), tableDataParam.getId()));
            instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getFinanceParentId),
                    new SubCondition(CriteriaOpsType.is.name(), tableDataParam.getFinanceParentId()));
        }
        List<Map> ret = new ArrayList<>();
        ViewProcessorManage processorManage = new ViewProcessorManage();

        List<TableHeaderItem> tableHeaderItems = context.getTableHeaderItems();
        //不分页查询
//        //instanceSearchParam.setPage(null);
        instanceInfos = instanceService.aggregateList(instanceSearchParam);

        long time2 = System.currentTimeMillis();
        if (null != instanceInfos && null != tableHeaderItems) {
            Set<RelateDataViewProcessor> relateDataViewProcess = processorManage.buildRelateDataViewProcessor(tableHeaderItems);
            Map<? extends Class<? extends RelateDataViewProcessor>, List<RelateDataViewProcessor>> collect = relateDataViewProcess.stream().collect(Collectors.groupingBy(s -> s.getClass()));
            Set<RelateDataViewProcessor> relateDataViewProcessors = new HashSet<>();
            collect.forEach((k,v)->{
                if(v!=null && v.size()>0){
                    RelateDataViewProcessor relateDataViewProcessor = v.get(0);
                    relateDataViewProcessors.add(relateDataViewProcessor);
                }
            });
            //初始化
            int seq = 0;
            for (InstanceInfoExtend instanceInfo : instanceInfos) {
                instanceInfo.setModelId(instanceInfo.getModelId());
                instanceInfo.setModelName(financeModelId2InfoMap.getOrDefault(instanceInfo.getFinanceParentId(), new ModelInfo()).getModelName());
                seq++;
                Map data = new LinkedHashMap();
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelGroupName), instanceInfo.getModelGroupName());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelName),instanceInfo.getModelName());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getModelId), instanceInfo.getModelId());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getGroupId), instanceInfo.getGroupId());
                data.put(CMDBTool.getFieldName(InstanceInfoExtend::getFinanceParentId), instanceInfo.getFinanceParentId());
                ret.add(data);
                if (tableDataParam.isShowAllField()) {
                    Map<String, Object> dataMap = instanceInfo.getData();
                    data.putAll(dataMap);
                }
                for (TableHeaderItem item : tableHeaderItems) {
                    Object value = instanceInfo.getValue(item.getField());
                    data.put(item.getField(), value);
                }
                //data.put(SEQ, seq);
                if (null == relateDataViewProcessors || relateDataViewProcessors.size() == 0) {
                    continue;
                }
                for (RelateDataViewProcessor processor : relateDataViewProcessors) {
                    processor.init(instanceInfo, data);
                }
            }

            if (null == relateDataViewProcessors || relateDataViewProcessors.size() == 0) {
                return ret;
            }
            //查询外部服务关联数据
            for (RelateDataViewProcessor processor : relateDataViewProcessors) {
                processor.selectRelateData(context);
            }

            //设置关联数据
            for (Map data : ret) {
                for (RelateDataViewProcessor processor : relateDataViewProcessors) {
                    processor.setRelateData(data);
                }
            }
        }
        long time3 = System.currentTimeMillis();
        log.info("获取实例列表数据:" + (time2 - time1) + "ms;权限数据转换:" + (time3 - time2) + "ms");
        return ret;
    }

    @Override
    public List<TableHeaderItem> genDefaultTableHeader(Class clazz) throws Exception {
        long time1 = System.currentTimeMillis();
        ModelPropertyServiceImpl modelService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
        // 查询所有金融元父模型的普通模型
        CustomModelServiceImpl customModelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam parentModelSearchParam = new ModelSearchParam();
        parentModelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule), new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
        List<ModelInfo> financeParentModelInfos = customModelService.getAllModelByParentGroup(parentModelSearchParam);
        List<String> financeParentModelIds = financeParentModelInfos.stream().map(ModelInfo::getId).toList();

        // 查询所有金融元父模型的普通模型
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        // 金融元模型id为分组id+父模型id
        if (!tableDataParam.getId().contains("_")) {
            // lookinstance接口按照模型调用
            modelSearchParam.setModelId(tableDataParam.getId());
        } else {
            // 视图列表接口调用
            modelSearchParam.setGroupId(tableDataParam.getId().split("_")[0]);
        }
        String financeParentModelId = tableDataParam.getFinanceParentId() != null ? tableDataParam.getFinanceParentId() : tableDataParam.getId().split("_")[1];
        modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getParentModelIds), new SubCondition(CriteriaOpsType.elemMatch.name(), Arrays.asList(financeParentModelId)));
        modelSearchParam.setPage(null);

        List<ModelInfo> modelInfos = customModelService.doSelectShowNormalModelByPath(modelSearchParam);
        List<PropertyInfo> propertyInfoList = new ArrayList<>();
        for (ModelInfo modelInfo : modelInfos) {
            propertyInfoList.addAll(modelInfo.getPropertyInfoList());
        }

        List<TableHeaderItem> tableHeaderItems = new ArrayList<>();
        addDefaultTableHeaderItem(tableHeaderItems);
        long time2 = System.currentTimeMillis();

        FieldViewAuthType fieldViewAuthType = tableDataParam.getAuthType() == null ? FieldViewAuthType.list : tableDataParam.getAuthType();
        Map<String, TableHeaderItem> itemMap = new HashMap<>();
        if (null != propertyInfoList) {
            for (PropertyInfo propertyInfo : propertyInfoList) {
                // 过滤没有金融元权限视图权限的数据
                Set<FieldViewAuthType> fieldViewAuthTypes = propertyInfo.getFileViewAuth(ViewTypeEnum.financeView.getName(), financeParentModelId);
                //只展示list权限的数据
                if (null == fieldViewAuthTypes || !fieldViewAuthTypes.contains(fieldViewAuthType)) {
                    continue;
                }

                // 若指定了金融元父模型 则过滤其它金融元父模型属性
                if (financeParentModelId != null && financeParentModelIds.contains(propertyInfo.getModelId())
                        && !financeParentModelId.equals(propertyInfo.getModelId())) {
                    continue;
                }

                TableHeaderItem item = null;
                ForeignKey foreignKey = propertyInfo.getForeignKey();
                if (null == foreignKey || !StringUtils.hasText(foreignKey.getKeyName())) {
                    item = new TableHeaderItem();
                } else {
                    RelatedDataType relatedDataType = RelatedDataType.valueOf(foreignKey.getRelatedDataType());
                    item = TableHeaderItemExt.build().keyName(foreignKey.getKeyName());
                    item.setParseType(relatedDataType);
                }

                item.setField(propertyInfo.getId());
                item.setHeaderName(propertyInfo.getName());
                item.setPropertyTypeId(propertyInfo.getPropertyTypeRef().getTypeId());
                boolean visible = propertyInfo.isDefaultListVisible();
                item.setVisible(visible);
                item.setFlex(flexNum);
                itemMap.put(item.getField(), item);
            }

            if (null != tableHeaderSort) {
                for (String key : tableHeaderSort) {
                    TableHeaderItem item = itemMap.get(key);
                    if (null != item) {
                        tableHeaderItems.add(item);
                        itemMap.remove(key);
                    }
                }

                tableHeaderItems.addAll(itemMap.values());
            }
        }
        long time3 = System.currentTimeMillis();
        log.info("TableProcessorCommonInstance::getCommonModelPropertyInfo耗时:" + (time2 - time1) + "ms;TableHeaderItem：" + (time3 - time2) + "ms");
        return tableHeaderItems;
    }

    private void addDefaultTableHeaderItem(List<TableHeaderItem> tableHeaderItems) {
        TableHeaderItem tableHeaderItem = TableHeaderItem.build().field(CMDBDefaultIdKey).headerName(CMDBDefaultIdName).visible(false).flex(100);
        tableHeaderItems.add(tableHeaderItem);
    }
}
